﻿using System;
using System.Collections.Generic;
using System.Linq;
using Coder.Workflow;
using Coder.Workflow.Stores;
using Fee.FileAttachs;
using Fee.Orders.FormalWorkflow;
using Fee.Stores;
using Identity;
using Microsoft.EntityFrameworkCore;
using Text.Helper;

namespace Fee.Orders.DesignWorkflow
{
    public class BudgetOrderManager<T> : WorkflowManager<T, BudgetOrder>
        where T : FeeDbContext

    {

        private readonly T _context;
        private readonly FileManager _fileManager;
        private readonly IWorkProcessStore<T> _workProcessStore;



        public BudgetOrderManager(T context,
          FileManager fileManager,
             IWorkProcessStore<T> workProcessStore,
            IWorkActivityStore<T> workActivityStore
        ) : base(context, workActivityStore)
        {
            _context = context;
            _fileManager = fileManager;

            _workProcessStore = workProcessStore;

        }

        public override BudgetOrder GetById(int id)
        {
            return _context.Set<BudgetOrder>().Include(f => f.WorkProcess)
                 .Include(f => f.Details).ThenInclude(f => f.Project)
                 .Include(f => f.Details).ThenInclude(f => f.Contract).ThenInclude(f => f.Vendor)
                 .Include(f => f.PlanCosts)
                 .Include(f => f.ConstructionTask).ThenInclude(f => f.Station).ThenInclude(f => f.District)
                 .Include(f => f.ConstructionTask).ThenInclude(f => f.Station).ThenInclude(f => f.OrderDistrict)
                 .Include(f => f.ConstructionTask).ThenInclude(f => f.Details).ThenInclude(f => f.Contract)
                 .ThenInclude(f => f.Vendor)
                 .FirstOrDefault(f => f.Id == id);
            ;
            ;

        }

        protected override IQueryable<WorkActivity> FillQuery(IQueryable<WorkActivity> workActivities)
        {
            return workActivities

                    .Include(f => (BudgetOrder)f.ProcessInstance).ThenInclude(f => f.Details).ThenInclude(f => f.Project)
                    .Include(f => (BudgetOrder)f.ProcessInstance).ThenInclude(f => f.Details).ThenInclude(f => f.Contract).ThenInclude(f => f.Vendor)
                    .Include(f => (BudgetOrder)f.ProcessInstance).ThenInclude(f => f.PlanCosts)
                    .Include(f => (BudgetOrder)f.ProcessInstance).ThenInclude(f => f.ConstructionTask).ThenInclude(f => f.Station).ThenInclude(f => f.District)
                    .Include(f => (BudgetOrder)f.ProcessInstance).ThenInclude(f => f.ConstructionTask).ThenInclude(f => f.Station).ThenInclude(f => f.OrderDistrict)
                    .Include(f => (BudgetOrder)f.ProcessInstance).ThenInclude(f => f.ConstructionTask).ThenInclude(f => f.Details).ThenInclude(f => f.Contract).ThenInclude(f => f.Vendor);
        }



        public BudgetOrder CreateOrder(ConstructionTask srcTask, User user, ConstructionType[] constructionType)
        {
            if (srcTask == null) throw new ArgumentNullException(nameof(srcTask));
            if (user == null) throw new ArgumentNullException(nameof(user));
            if (srcTask.Status != ConstructionTaskStatus.PreAuthed) throw new WorkflowException("只有'预委托完'才能发起设计院委托");

            var wf = _workProcessStore.Get<BudgetOrderWorkProcess>(BudgetOrder.DesignPlanCostWorkflowName);

            var delegateOrder = new BudgetOrder(wf, user)
            {
                ConstructionTask = srcTask,
                User = user
            };

            foreach (var taskDetail in srcTask.Details)
                // 生成这个订单的时候，排除了设计的，
                if (constructionType.Contains(taskDetail.ConstructionType))
                    delegateOrder.Details.Add(taskDetail.CreateOrderDetail());
            //预算

            if (srcTask.CostDetails.Any())
            {
                foreach (var planDetail in srcTask.PlanCosts)
                {
                    delegateOrder.PlanCosts.Add(new BudgetOrderPlanCost(planDetail));
                }
            }
            else
            {
                foreach (ConstructionType type in Enum.GetValues(typeof(ConstructionType)))
                {
                    delegateOrder.PlanCosts.Add(new BudgetOrderPlanCost()
                    {
                        Type = type
                    });
                }
            }

            //delegateOrder.ThirdPartyWorkflowId = srcTask.Station.ThirdPartyWorkOrderId;

            _context.Update(delegateOrder);
            _context.SaveChanges();
            return delegateOrder;
        }


        public override IEnumerable<WorkActivity> Start(BudgetOrder order)
        {
            if (order.ConstructionTask == null) _context.Entry(order).Reference(a => a.ConstructionTask).Load();
            order.ConstructionTask.Status = ConstructionTaskStatus.Designing;
            return base.Start(order);
        }

        public IEnumerable<WorkActivity> GetMyTask(DelegateWorkActivitySearch searcher, out int total)
        {
            var query = searcher.ForDelegateBase(_context);

            total = query.Count();

            query = WorkActivityStore.IncludeAllDelegateBase(query);

            return query.Skip(searcher.GetSkip()).Take(searcher.GetTake()).ToList();


        }

        protected override void OnProcessComplete(ProcessInstance instance)
        {
            base.OnProcessComplete(instance);
            var order = (BudgetOrder)instance;
            order.ConstructionTask.Status = ConstructionTaskStatus.Designed;


            foreach (var attach in order.Attaches)
            {
                var taskPath = _fileManager.GetConstructionTaskFolder(order.ConstructionTask.Id);
                attach.File.CopyTo(taskPath);
                var taskAttach = new ConstructionTaskFileAttach()
                {
                    File = new FileAttach(attach.File.Name, taskPath)
                    {
                        UploadUser = attach.File.UploadUser
                    },
                    Task = order.ConstructionTask
                };

                order.ConstructionTask.Attaches.Add(taskAttach);



            }
        }
    }
}